package com.zhx.distributedredission.annotation;


import com.zhx.distributedredission.RedissonLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;


/**
 * 分布式锁注解解析器
 * @author Yuqiang
 */
@Aspect
@Component
@Slf4j
public class DistributedLockHandler {

    @Autowired
    RedissonLock redissonLock;


    @Around("@annotation(distributedLock)")
    public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        log.info("[开始]执行RedisLock环绕通知,获取Redis分布式锁开始");
        //获取锁名称
        String lockName = distributedLock.value();
        Object[] objs = joinPoint.getArgs();
        /**
         * 获取aop参数上,@LockParameter 注解标注的属性值, 然后自动拼接 分布式锁的值
         */
        //获取所有参数上的注解,返回一个二维数据, 第一个是参数, 第二个是参数上的注解,(参数可以标注多个注解,所以参数注解也是个数组)
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        if (parameterAnnotations != null && parameterAnnotations.length > 0) {
            for (int k = 0; k < parameterAnnotations.length; k++) {
                Annotation[] parameterAnnotation = parameterAnnotations[k];
                if (parameterAnnotation != null && parameterAnnotation.length > 0) {
                    for (int j = 0; j < parameterAnnotation.length; j++) {
                        Annotation annotation = parameterAnnotations[k][j];
                        if (annotation.annotationType().equals(LockParameter.class)) {
                            String LockParameterValue = (String) objs[k];
                            lockName = lockName + LockParameterValue;
                            continue;
                        }
                    }
                }
            }
        }

        //获取超时时间，默认10秒
        int leaseTime = distributedLock.leaseTime();
        this.redissonLock.lock(lockName, leaseTime);
        try {
            log.info("获取Redis分布式锁[成功]，加锁完成，开始执行业务逻辑...");
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            log.error("获取Redis分布式锁[异常]，加锁失败", throwable);
            throwable.printStackTrace();
        } finally {
            //如果该线程还持有该锁，那么释放该锁。如果该线程不持有该锁，说明该线程的锁已到过期时间，自动释放锁
            if (this.redissonLock.isHeldByCurrentThread(lockName)) {
                this.redissonLock.unlock(lockName);
            }
        }
        log.info("释放Redis分布式锁[成功]，解锁完成，结束业务逻辑...");
        return null;
    }
}
